﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace B10_Ex02_Elad_034695114_Meyron_026607788
{
    using Infrastructure.ObjectModel;
    using Infrastructure.ServiceInterfaces;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Graphics;
    using Infrastructure.Managers;
    using B10_Ex02_Elad_034695114_Meyron_026607788;
    using B10_Ex02_Elad_034695114_Meyron_026607788.ObjectModel;
    using B10_Ex02_EladLebovitch_034695114.Interfaces;

    public delegate void PlayerShipDestroyed(object sender, EventArgs e);
    public delegate void PlayerShipScored(object sender, SpaceShipScoredEventArgs e);

    public class SpaceShip : Sprite, ICollidable2D, IPlayerObjects
    {
        #region Data Members
        public Keys LeftMoveKey { get; set; }
        public Keys RightMoveKey { get; set; }
        public Keys FireKey { get; set; }
        public int StartLocationOffset { get; set; }
        public bool m_IsDying = false;

        public event PlayerShipDestroyed PlayerShipDestroyedEvent;
        public event PlayerShipScored PlayerShipScoredEvent;

        public List<Sprite> Bullets
        {
            get
            {
                return m_Bullets;
            }

            protected set
            {
                m_Bullets = value;
            }
        }

        public bool IsControledByMouse
        {
            get;
            set;
        } 
        #endregion

        #region Consts and members
        private const float k_Velocity = 175f;
        private const float k_MaxBullets = 2;
        private const float k_BulletVelocity = 200f;
        private const int k_RotationSpeed = 1;
        private const int k_DissappearSpeed = 4;
        private const int k_BulletSize = 6;
        private IInputManager m_InputManager;
        private List<Sprite> m_Bullets;
        #endregion

        #region CTor and Init
        /// <summary>
        /// Initilizes a new instance of spaceship
        /// </summary>
        /// <param name="i_Game">The owenr</param>
        public SpaceShip(Game i_Game, string i_assetName, bool i_ShouldControledByMouse)
            : base(i_assetName, i_Game)
        {
            // Register to game components
            ((ICollisionsManager)i_Game.Services.GetService(typeof(ICollisionsManager))).AddObjectToMonitor(this);

            Bullets = new List<Sprite>();
            PlayerBullet plyCurrBullet;
            IsControledByMouse = i_ShouldControledByMouse;

            // Build k_maxbullets for the ship to use
            for (int i = 0; i < k_MaxBullets; i++)
            {
                plyCurrBullet = new PlayerBullet(this.Game, Vector2.Zero);
                plyCurrBullet.Enabled = false;
                plyCurrBullet.Visible = false;
                plyCurrBullet.BulletCollidedWithEnemyEvent += new BulletCollided(plyCurrBullet_BulletCollidedWithEnemyEvent);
                Bullets.Add(plyCurrBullet);
            }
        }

        /// <summary>
        /// When the ship hits somthing
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void plyCurrBullet_BulletCollidedWithEnemyEvent(object sender, BulletCollidedEventArgs e)
        {
            // Stop the bullet
            PlayerBullet plyCurr = sender as PlayerBullet;
            
            // Check if somone wants to knwo
            if (PlayerShipScoredEvent != null)
            {
                PlayerShipScoredEvent(this, new SpaceShipScoredEventArgs(e.EnemyDestroyed.Points));
            }
        }

        /// <summary>
        /// Sets init stuff
        /// </summary>
        public override void Initialize()
        {
            // Uses a lot of input manager
            m_InputManager = Game.Services.GetService(typeof(IInputManager)) as IInputManager;
            base.Initialize();
        } 
        #endregion

        #region Other Methods

        protected override void InitOrigins()
        {
            // put in bottom right of view port:
            // get the bottom and right
            float x = (float)Width * (2 + StartLocationOffset);
            float y = (float)GraphicsDevice.Viewport.Height;

            // offset:
            x -= this.Width / 2;
            y -= this.Height / 2;

            // put it a little bit higher:
            y -= 30;

            // Set the new position
            this.PositionOfOrigin = new Vector2(x, y);
            this.RotationOrigin = this.SourceRectangleCenter;
        }

        /// <summary>
        /// Occours all the time
        /// </summary>
        /// <param name="gameTime">The time passed</param>
        public override void Update(GameTime gameTime)
        {
            // Check if we died or all is ok
            if (!m_IsDying)
            {
                // Look if we are moving
                checkMovement();

                // Check if we were out of bounds
                this.PositionOfOrigin = new Vector2(
                                MathHelper.Clamp(
                                this.PositionOfOrigin.X,
                                1,
                                Game.GraphicsDevice.Viewport.Width - this.Width - 1),
                                this.PositionOfOrigin.Y);

                this.handleBullets();

                // Called anyways
                base.Update(gameTime);
            }
            else
            {
                // We are dying
                if (this.Opacity > 0)
                {
                    this.SpinAndDisappear(k_RotationSpeed, k_DissappearSpeed);
                }
                // We are completely dead
                else
                {
                    // Init the parameters to the original before death
                    this.Opacity = 100;
                    this.Rotation = 0;
                    m_IsDying = false;

                    // Don't know what to do - tell everyone and that's it
                    if (PlayerShipDestroyedEvent != null)
                    {
                        PlayerShipDestroyedEvent(this, new EventArgs());
                    }
                }
            }
        }

        private void checkMovement()
        {
            // Check if the spaceship is moving left
            if (m_InputManager.KeyboardState.IsKeyDown(this.LeftMoveKey) || 
               ((m_InputManager.MousePositionDelta.X < 0) && (IsControledByMouse)))
            {
                // Set the speed to left
                m_Velocity.X = k_Velocity * -1;
            }
            else if (m_InputManager.KeyboardState.IsKeyDown(this.RightMoveKey) || 
                    ((m_InputManager.MousePositionDelta.X > 0) && (IsControledByMouse)))
            {
                // Set the speed to right
                m_Velocity.X = k_Velocity;
            }
            else
            {
                // Set to zero
                m_Velocity.X = 0;
            }
        }

        /// <summary>
        /// Fires a bullet to the top
        /// </summary>
        protected void handleBullets()
        {
            // Check if the player fired
            if (m_InputManager.KeyPressed(this.FireKey) || (m_InputManager.ButtonPressed(eInputButtons.Left) && (IsControledByMouse)))
            {
                // Get a bullet if possible
                PlayerBullet plyRecycledBullet = this.Bullets.Find(bullet => bullet.Enabled == false) as PlayerBullet;

                // Check if the player is allowed to fire another bullet (checks all enabled bullets)
                if (plyRecycledBullet != null)
                {
                    // Create and fire a bullet using the spaceship location
                    plyRecycledBullet.PositionOfOrigin = new Vector2(this.PositionOfOrigin.X + this.SourceRectangleCenter.X - k_BulletSize / 2,
                                                                     PositionOfOrigin.Y - (this.Height / 2));
                    // Set the bullet to visible and fire it
                    plyRecycledBullet.Enabled = true;
                    plyRecycledBullet.Visible = true;

                    (Game.Services.GetService(typeof(ISoundManeger)) as ISoundManeger).PlayCue("Fire");
                }
            }
        }

        /// <summary>
        /// Sets collided with enemy bullets
        /// </summary>
        /// <param name="i_Collidable"></param>
        public override void Collided(ICollidable i_Collidable)
        {
            // Check that it was a harmful stuff
            if (i_Collidable is IHarmful && i_Collidable is IEnemyObjects)
            {
                (Game.Services.GetService(typeof(ISoundManeger)) as ISoundManeger).PlayCue("LifeDie");
                m_IsDying = true;
            }
        }

        #endregion
    }

    public class SpaceShipScoredEventArgs : EventArgs
    {
        public SpaceShipScoredEventArgs(int i_Points)
        {
            Points = i_Points;
        }
        
        public int Points
        {
            get;
            set;
        }
    }
}